package cn.lg.soar.common.data;

/**
 * 自定义64进制工具
 * 转换和解析效率几乎一样，都极高
 * 测试机器：Intel(R)Core(TM) i5-6500 CPU @3.20GHz 3.20 GHz 内存 12.0GB(11.9 GB可用)
 * 测试结果：1亿次转换总耗时 1765 毫秒，平均一次转换耗时 0.01765 纳秒
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class Soar64 {

    private final static char[] chars = "-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".toCharArray();
    private final static byte[] bsa_z = { 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 };
    private final static byte[] bsA_Z = { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36 };
    private final static byte[] bs0_1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    /**
     * soar64 转 long 类型数据
     * @param soar64
     * @return
     */
    public static long toLong(String soar64){
        char[] cs = soar64.toCharArray();
        if (cs.length > 11 || cs.length == 11 && cs[0] > 'E') {
            throw new RuntimeException("Out of range");
        }
        long l = 0;
        for (int i = 0; i < cs.length; i++) {
            l <<= 6;
            l |= parseValue(cs[i]);
        }
        return l;
    }

    /**
     * long 类型数据 转 soar64
     * @param value 值
     * @param resultLen 结果长度（可规定结果字符串长度，超出的部分抛弃）
     * @param fixedLen 是否固定长度（固定长度性能高，但有无效字符占空间，就像十进制前面的0是无效字符）
     * @return
     */
    public static String ofLong(long value, int resultLen, boolean fixedLen){
        if (resultLen > 11) {
            throw new RuntimeException("resultLen Range 1 to 11");
        }
        char[] result = new char[resultLen];
        for (int i = result.length - 1; i >= 0; i--) {
            result[i] = chars[ (byte)(value & 0x3F) ];
            value >>>= 6;
        }
        if (fixedLen) {
            return String.valueOf(result);
        }
        return String.valueOf(result).replaceAll("^-*", "");
    }
    public static String ofLong(long value, int resultLen){
        return ofLong(value, resultLen, false);
    }
    public static String ofLong(long l) {
        return ofLong(l, 11, false);
    }

    public static String ofLong8(long l) {
        return ofLong(l, 8, false);
    }

    public static String ofLong6(long l) {
        return ofLong(l, 6, false);
    }


    /**
     * soar64 转 int 类型数据
     * @param soar64
     * @return
     */
    public static long toInt(String soar64){
        char[] cs = soar64.toCharArray();
        if (cs.length > 6 || cs.length == 6 && cs[0] > '2') {
            throw new RuntimeException("Out of range");
        }
        int l = 0;
        for (int i = 0; i < cs.length; i++) {
            l <<= 6;
            l |= parseValue(cs[i]);
        }
        return l;
    }

    /**
     * int 类型数据 转 soar64
     * @param value 值
     * @param resultLen 结果长度（可规定结果字符串长度，超出的部分抛弃）
     * @param fixedLen 是否固定长度（固定长度性能高，但有无效字符占空间，就像十进制前面的0是无效字符）
     * @return
     */
    public static String ofInt(int value, int resultLen, boolean fixedLen){
        if (resultLen > 6) {
            throw new RuntimeException("resultLen Range 1 to 6");
        }
        char[] result = new char[resultLen];
        for (int i = result.length - 1; i >= 0; i--) {
            result[i] = chars[ (byte)(value & 0x3F) ];
            value >>>= 6;
        }
        if (fixedLen) {
            return String.valueOf(result);
        }
        return String.valueOf(result).replaceAll("^-*", "");
    }
    public static String ofInt(int value, int resultLen){
        return ofInt(value, resultLen, false);
    }
    public static String ofInt(int value) {
        return ofInt(value, 6, false);
    }

    public static String ofInt4(int value) {
        return ofInt(value, 4, false);
    }

    private static int parseValue(int x) {
        if (97 <= x) {
            return bsa_z[ x -'a' ];
        }
        if (95 == x) {
            return 37;
        }
        if (65 <= x) {
            return bsA_Z[ x -'A' ];
        }
        if (48 <= x) {
            return bs0_1[ x -'0' ];
        }
        if (45 == x) {
            return 0;
        }
        throw new RuntimeException("Format error");
    }
}
